import { Injectable, Injector } from '@angular/core';
import { DomService } from './dom.service';
import { MessagerService } from '@farris/ui-messager';
import { FormBasicService } from '../services/form-basic.service';
import { FormWebCmd } from '../entity';
import { forkJoin, Observable, of, Subject } from 'rxjs';
import { retryWhen, scan, delay } from 'rxjs/operators';
import { catchError, map, switchMap } from 'rxjs/operators';
import { cloneDeep } from 'lodash-es';
import { IdService } from '@farris/ui-common';
import { WebCmpBuilderService } from './web-cmp-builder.service';
import { IControlService } from '@farris/designer-element';
import { DesignerHostSettingService } from './designer-host.service';
import { LoadingService } from '@farris/ui-loading';
import { FarrisMetadataDto, FarrisMetadataService } from './metadata-service';
import { WebCommandMetadataConvertor } from '../web-command-converter/web-command-metadata';

@Injectable({
  providedIn: 'root'
})
export class WebCmdService {
  controlService: IControlService;
  constructor(
    public domService: DomService,
    public msgService: MessagerService,
    public metadataService: FarrisMetadataService,
    public formBasicService: FormBasicService,
    public idService: IdService,
    public webCmpBuilderService: WebCmpBuilderService,
    public injector: Injector,
    public loadingService: LoadingService,
  ) { }

  /** 单个内置构件控制器 */
  internalCommandListItem = {
    controllerName: {
      label: '',
      name: '',
      id: '',
    },
    controllerList: [
    ]
  }
  /** 控制器下的命令列表 */
  controllerListItem = {
    label: '',
    name: '',
    id: '',
    handlerName: '',
    /** 当前命令需要选择目标组件 */
    showTargetComponent: false,
    /** 当前命令选择的目标组件的id */
    cmpId: '',
    componentLists: [],
    isNewGenerated: undefined,
    isRTCmd: undefined,
    isInvalid: false,
    property: []
  }
  /** 命令列表下的参数 */
  propertyItem: any;
  /** 内置构件控制器 */
  internalCommandList = [];
  /** 已绑定事件列表 */
  boundEventsList: any;
  /** dom中的webCmds节点 */
  webCmds: any;
  /** dom中的视图模型数据 */
  viewModelData: any;


  newControllerMethodBindingInfo: {
    controlData: any,
    componentId: string,
    viewModelId: string,
    eventCode: string,
    methodCode: string,
    methodName: string,
    setPropertyRelates?: any
  };

  /** 0.获取webcmd控制器（其参数为空）*/
  checkCommands(): Observable<any> {
    const loading = this.loadingService.show({ message: '数据加载中，请稍候....' });
    const subject = new Subject<any>();
    this.loadWebcmd().subscribe(webCmds => {
      // 设计器自动补充的属性，不记录变更
      window['suspendChangesOnForm'] = true;

      this.webCmds = cloneDeep(webCmds);
      this.generateInternalCommandList();
      this.checkViewModelCommands(webCmds);
      this.syncActions();
      loading.close();

      window['suspendChangesOnForm'] = false;

      subject.next(true)
    }, err => {
      this.msgService.warning(err);
      loading.close();
      subject.next(true)
    });
    return subject;
  }

  /** 1.生成webcmd控制器列表 */
  loadWebcmd() {
    const retryWithDelay = (count: number, delayTime: number) => {
      return retryWhen((errors) => {
        return errors.pipe(
          scan((errCount) => {
            if (errCount >= count) {
              throw errors;
            }
            return errCount + 1;
          }, 0),
          delay(delayTime)
        );
      });
    };
    return this.loadWebCmdsInCurrentPath().pipe(
      switchMap(() => {
        const webcmdInfos = this.domService.getWebCmds();
        const obs = [];
        for (const webcmdInfo of webcmdInfos) {
          const metadataServ = this.metadataService.getMetadata(webcmdInfo.id);
          const ob = metadataServ.pipe(
            // 补充控制器编号、命名空间
            map(metadata => {
              // 设计器自动补充的属性，不记录变更
              window['suspendChangesOnForm'] = true;

              webcmdInfo.code = webcmdInfo.code ? webcmdInfo.code : metadata.code;
              webcmdInfo.nameSpace = webcmdInfo.nameSpace ? webcmdInfo.nameSpace : metadata.nameSpace;

              window['suspendChangesOnForm'] = false;
              return metadata;
            }),
            retryWithDelay(3, 330),  // 如果拉取元数据包失败，可能是后端接口暂时性异常，重试3次均失败再弹出提示
            catchError(() => {
              // 1、当前表单中引用了构件中的方法：那么找不到构件时，提示用户是否要移除构件的引用。
              // 2、当前表单没有引用构件中的任何方法：那么找不到构件时，自动移除构件引用信息，没有提示信息。
              if (webcmdInfo.refedHandlers && webcmdInfo.refedHandlers.length) {
                this.msgService.question(`获取元数据${webcmdInfo.name}失败，是否移除表单的引用？`, () => {
                  this.domService.getDomJson().module.webcmds = this.domService.getWebCmds().filter(webCmd => webCmd.id !== webcmdInfo.id);
                });
              } else {
                this.domService.getDomJson().module.webcmds = this.domService.getWebCmds().filter(webCmd => webCmd.id !== webcmdInfo.id);
              }
              return of(false);
            })
          );
          obs.push(ob);
        }
        let loadingObservable: Observable<FarrisMetadataDto[]>;
        if (obs.length) {
          loadingObservable = forkJoin(obs);
        } else {
          loadingObservable = of([]);
        }
        // 每次加载重新请求。
        return loadingObservable.pipe(
          map(metadataList => {
            return metadataList.filter(item => !!item).map(item => new WebCommandMetadataConvertor().InitFromJobject(JSON.parse(item.content)));
          })
        );
      })
    );

  }
  /** 1-1.将当前表单相关的自定义构件追加到webCmds中 */
  private loadWebCmdsInCurrentPath(): Observable<any> {
    const webcmdInfos = this.domService.getWebCmds();
    const result = this.metadataService.getMetadataList('.webcmd');
    const subject = new Subject<any>();
    result.subscribe(list => {
      if (!list) {
        subject.next();
        return;
      }
      for (const item of list) {
        let extendProperty: any;
        try {
          extendProperty = JSON.parse(item.extendProperty);
        } catch (e) { }

        // 比对表单编号，若不匹配说明是其他表单关联的自定义构件
        if (extendProperty && extendProperty.FormCode !== this.formBasicService.formMetaBasicInfo.code) {
          continue;
        }

        // 只要是属于此表单的都需要加载，除非是已经添加到表单中
        if (!webcmdInfos.find(webcmdInfo => item.id === webcmdInfo.id)) {
          // 画布渲染过程中，可能会在控件上补充属性，这种变更用户不感知，所以不需要通知IDE框架
          window['suspendChangesOnForm'] = true;
          const webcmd: FormWebCmd = {
            id: item.id,
            path: item.relativePath,
            name: item.fileName,
            refedHandlers: []
          };
          webcmdInfos.push(webcmd);

          window['suspendChangesOnForm'] = false;
        }
      }
      subject.next();
    });
    return subject;
  }

  /** 2.生成内置构件中的控制器列表数据 */
  generateInternalCommandList() {
    this.webCmds = cloneDeep(this.getUniqueValue(this.webCmds, 'Id'));
    this.internalCommandList = [];
    this.webCmds.forEach(controller => {
      this.internalCommandListItem.controllerName = {
        label: controller.Code,
        name: controller.Name,
        id: controller.Id,
      }
      if (!controller.Commands) {
        controller['Commands'] = [];
      }
      controller.Commands.forEach(command => {
        this.controllerListItem.label = command.Code;
        this.controllerListItem.name = command.Name;
        this.controllerListItem.id = command.Id;
        this.controllerListItem.handlerName = command.Code;
        if (command.Parameters) {
          command.Parameters.forEach(params => {
            this.propertyItem = {
              id: params.Id,
              name: cloneDeep(params.Code),
              value: '',
              shownName: params.Name,
              description: params.Description,
              editorType: cloneDeep(params.EditorType),
              isRetVal: params.IsRetVal,
              parameterType: params.parameterType,
              origin: cloneDeep(params)
            }
            this.controllerListItem.property.push(cloneDeep(this.propertyItem));
          });
        }
        else {
          command['Parameters'] = [];
          this.controllerListItem.property = [];
        }
        this.internalCommandListItem.controllerList.push(cloneDeep(this.controllerListItem));
        this.controllerListItem.property = [];
      });
      this.internalCommandList.push(cloneDeep(this.internalCommandListItem));
      this.internalCommandListItem.controllerList = [];
    });
    return this.internalCommandList;

  }
  /** 2-1.去重 */
  getUniqueValue(itemWithSameValue, identifier) {
    let value = cloneDeep(itemWithSameValue);
    for (let i = 0; i < value.length; i++) {
      for (let j = i + 1; j < value.length; j++) {
        if (value[i][identifier] == value[j][identifier]) {
          value.splice(j, 1);
          j--;
        }
      }
    }
    itemWithSameValue = cloneDeep(value);
    return itemWithSameValue;
  }

  /** 3.检查视图模型的命令是否符合存储规范 */
  checkViewModelCommands(webCmds) {

    // 设计器自动补充的属性，不记录变更
    window['suspendChangesOnForm'] = true;

    this.domService.viewmodels.forEach(viewModel => {
      if (!viewModel.commands) {
        return;
      }
      viewModel.commands.map(curCmd => {
        const webCmd = webCmds.find(item => item.Id === curCmd.cmpId);
        if (!webCmd) {
          curCmd.isInvalid = true;
          return;
        }
        const commandInWebCmd = webCmd.Commands.find(c => c.Code === curCmd.handlerName);

        if (commandInWebCmd) {
          curCmd.isInvalid = false;

          // 将表单中记录的参数名称更新为控制器中的参数名称
          if (curCmd.params && curCmd.params.length && commandInWebCmd.Parameters && commandInWebCmd.Parameters.length) {
            curCmd.params.forEach((curParam) => {
              const paramInWebCmd = commandInWebCmd.Parameters.find(param => param.Code === curParam.name);
              if (paramInWebCmd) {
                curParam.shownName = paramInWebCmd.Name;
                delete curParam.description;
              }
            });
          }
        } else {
          curCmd.isInvalid = true;
        }
      });

    });

    window['suspendChangesOnForm'] = false;
  }

  /** 4.渲染表单取出所有的已绑定事件，同步至actions节点 */
  syncActions() {
    if (this.webCmds) {
      let components = cloneDeep(this.domService.module.components);
      components = components.filter(c => !c.fakeDel);
      let findEvents = [];
      let allBoundEvents = this.findBoundEvent(components, findEvents, 'root-viewmodel');
      if (this.domService.module.toolbar) {
        allBoundEvents = this.findBoundEventInToolbar(this.domService.module.toolbar, allBoundEvents);
      }
      this.getUniqueEvent(allBoundEvents);
      let array = [];
      const viewModel = cloneDeep(this.domService.module.viewmodels);
      if (allBoundEvents.length != 0) {
        allBoundEvents = this.setActions(this.getComponentId(this.matchWebcmd(this.matchVM(allBoundEvents, viewModel))), 0, array);
      }
      this.domService.module.actions = cloneDeep(allBoundEvents);
    }
  }
  /** 4-1-1.遍历components节点，找到所有事件 */
  findBoundEvent(components, findEvents, viewModelId, excludedEvents?: string[]) {
    this.controlService = this.injector.get(DesignerHostSettingService).controlService;
    components.forEach((componentsItem) => {
      if (componentsItem['viewModel']) { viewModelId = componentsItem['viewModel'] }
      if (componentsItem['contents']) {
        this.findBoundEvent(componentsItem['contents'], findEvents, viewModelId);
      }
      if (componentsItem['items']) {
        this.findBoundEvent(componentsItem['items'], findEvents, viewModelId);
      }
      if (componentsItem['children']) {
        this.findBoundEvent(componentsItem['children'], findEvents, viewModelId);
      }
      if (componentsItem['fields']) {
        this.findBoundEvent(componentsItem['fields'], findEvents, viewModelId);
      }
      if (componentsItem['editor']) {
        let editor = [];
        editor.push(cloneDeep(componentsItem['editor']));
        this.findBoundEvent(editor, findEvents, viewModelId, ['linkedLabelClick']);
      }
      if (componentsItem['toolbar']) {
        if (componentsItem['toolbar']['contents']) {
          this.findBoundEvent(componentsItem['toolbar']['contents'], findEvents, viewModelId);
        }
        //移动：导航工具栏
        if (componentsItem['toolbar']['items']) {
          this.findBoundEvent(componentsItem['toolbar']['items'], findEvents, viewModelId);
        }
      }
      // ListView
      if (componentsItem['type'] == "ListView") {
        if (componentsItem['contentTemplate']) {
          const contentTemplateDom = componentsItem['contentTemplate'];
          if (contentTemplateDom['toolbar']) {
            if (contentTemplateDom['toolbar']['contents']) {
              this.findBoundEvent(contentTemplateDom['toolbar']['contents'], findEvents, viewModelId);
            }
          }
        }
        //移动：列表滑动
        if (componentsItem['swipeToolbar'] && componentsItem['swipeToolbar']['items']) {
          this.findBoundEvent(componentsItem['swipeToolbar']['items'], findEvents, viewModelId);
        }

      }
      // table类型
      if (componentsItem['type'] == "Table" && componentsItem['rows']) {
        const rows = componentsItem['rows'];
        rows.forEach(rowsItem => {
          if (rowsItem['columns']) {
            const columns = rowsItem['columns'];
            columns.forEach(columnsItem => {
              if (columnsItem['editor']) {
                this.findBoundEvent([columnsItem['editor']], findEvents, viewModelId);
              }
            });
          }
        })
      }
      // 筛选方案
      if (componentsItem['fieldConfigs']) {
        const fieldConfigs = componentsItem['fieldConfigs'];
        fieldConfigs.forEach(fieldConfigsItem => {
          if (fieldConfigsItem['control']) {
            this.findBoundEvent([fieldConfigsItem['control']], findEvents, viewModelId);
          }
        });
      }
      // 筛选条
      if (componentsItem['filterList']) {
        const fieldConfigs = componentsItem['filterList'];
        fieldConfigs.forEach(fieldConfigsItem => {
          if (fieldConfigsItem['control']) {
            this.findBoundEvent([fieldConfigsItem['control']], findEvents, viewModelId);
          }
        });
      }

      // 侧边栏
      if (componentsItem['type'] == "Sidebar" && componentsItem['toolbar'] && componentsItem['toolbar']['items']) {
        this.findBoundEvent(componentsItem['toolbar']['items'], findEvents, viewModelId);
      }

      // 智能输入框的弹出表单模式
      if (componentsItem['modalConfig'] && componentsItem['modalConfig']['footerButtons'] && componentsItem['modalConfig']['footerButtons'].length) {
        this.findBoundEvent(componentsItem['modalConfig']['footerButtons'], findEvents, viewModelId);
      }

      // 列表右键菜单中的按钮
      if (componentsItem['type'] == "DataGrid" && componentsItem['contextMenuItems'] && componentsItem['contextMenuItems'].length) {
        this.findBoundEvent(componentsItem['contextMenuItems'], findEvents, viewModelId);
      }

      // 查询结果工具栏中的按钮
      if (componentsItem['type'] == "QdpFramework" && componentsItem['inputTemplate'] && componentsItem['inputTemplate'].length) {
        this.findBoundEvent(componentsItem['inputTemplate'], findEvents, viewModelId);
      }

      const controlEventPropertyIDList = this.controlService.getControlEventPropertyIDList();
      let eventKeys = Object.keys(controlEventPropertyIDList);
      for (let i = 0; i < eventKeys.length; i++) {
        if (excludedEvents && excludedEvents.length && excludedEvents.includes(eventKeys[i])) {
          continue;
        }
        let exist = componentsItem.hasOwnProperty(eventKeys[i]);
        if (exist && componentsItem[eventKeys[i]]) {
          // 判定三段式路径
          let paths = componentsItem[eventKeys[i]].includes('.') ? componentsItem[eventKeys[i]].split('.') : undefined;
          const vmId = paths != undefined ? paths[1] : viewModelId;
          const cmdLabel = paths != undefined ? paths[2] : componentsItem[eventKeys[i]];
          let findEventsItem = {
            id: componentsItem['id'],
            eventLabel: eventKeys[i],
            eventName: controlEventPropertyIDList[eventKeys[i]],
            commandLabel: cmdLabel,
            viewModelId: vmId
          }
          findEvents.push(cloneDeep(findEventsItem));
        }
      }
    })
    return findEvents;
  }
  /** 4-1-2.遍历查看是否存在toolbar节点，若有，则找到所有事件 */
  findBoundEventInToolbar(toolbar, findEvents) {
    if (toolbar['items']) {
      const items = toolbar['items'];
      const vmKeys = Object.keys(items);
      for (let j = 0; j < vmKeys.length; j++) {
        const vmValue = items[vmKeys[j]];
        vmValue.forEach(vmValueItem => {
          const controlEventPropertyIDList = this.controlService.getControlEventPropertyIDList();
          let eventKeys = Object.keys(controlEventPropertyIDList);
          for (let i = 0; i < eventKeys.length; i++) {
            let exist = vmValueItem.hasOwnProperty(eventKeys[i]);
            if (exist && vmValueItem[eventKeys[i]]) {
              // 判定三段式路径
              let paths = vmValueItem[eventKeys[i]].includes('.') ? vmValueItem[eventKeys[i]].split('.') : undefined;
              const vmId = paths != undefined ? paths[1] : vmKeys[j];
              const cmdLabel = paths != undefined ? paths[2] : vmValueItem[eventKeys[i]];
              let findEventsItem = {
                id: vmValueItem['id'],
                eventLabel: eventKeys[i],
                eventName: controlEventPropertyIDList[eventKeys[i]],
                commandLabel: cmdLabel,
                viewModelId: vmId
              }
              findEvents.push(cloneDeep(findEventsItem));
            }

            // 识别二级按钮
            if (vmValueItem.items && vmValueItem.items.length) {
              vmValueItem.items.forEach(childItem => {
                if (!childItem[eventKeys[i]]) {
                  return;
                }
                const paths = childItem[eventKeys[i]].includes('.') ? childItem[eventKeys[i]].split('.') : undefined;
                const vmId = paths !== undefined ? paths[1] : vmKeys[j];
                const cmdLabel = paths !== undefined ? paths[2] : childItem[eventKeys[i]];
                const findEventsItem = {
                  id: childItem['id'],
                  eventLabel: eventKeys[i],
                  eventName: controlEventPropertyIDList[eventKeys[i]],
                  commandLabel: cmdLabel,
                  viewModelId: vmId
                };
                findEvents.push(cloneDeep(findEventsItem));
              })

            }
          }
        })
      }
    }
    return findEvents;
  }
  /** 4-2.去重-去除特殊情况下存储的相同事件及命令 */
  getUniqueEvent(allBoundEvents) {
    let value = cloneDeep(allBoundEvents);
    for (let i = 0; i < value.length; i++) {
      for (let j = i + 1; j < value.length; j++) {
        if (value[i]['id'] == value[j]['id'] && value[i]['eventLabel'] == value[j]['eventLabel']) {
          value.splice(j, 1);
          j--;
        }
      }
    }
    allBoundEvents = cloneDeep(value);
    return allBoundEvents;
  }
  /** 4-3.根据遍历components和toolbar得出的所有事件，结合viewmodel和webcmd,得到参数值 */
  matchVM(allBoundEvents, viewModel) {
    let updatedBoundEvents = [];
    allBoundEvents.forEach(boundEvenItem => {
      viewModel.forEach(viewModelItem => {
        if (viewModelItem.id == boundEvenItem.viewModelId) {
          viewModelItem.commands.forEach(commandItem => {
            if (commandItem.code == boundEvenItem.commandLabel) {
              let event = {
                id: boundEvenItem.id,
                eventLabel: boundEvenItem.eventLabel,
                eventName: boundEvenItem.eventName,
                viewModelId: boundEvenItem.viewModelId,
                commandId: commandItem.id,
                commandLabel: boundEvenItem.commandLabel,
                commandName: commandItem.name,
                handlerName: commandItem.handlerName,
                cmpId: commandItem.cmpId,
                isNewGenerated: commandItem.isNewGenerated || false,
                isRTCmd: commandItem['isRTCmd'],
                isInvalid: commandItem.isInvalid || false,
                params: cloneDeep(commandItem.params),
                controllerId: '',
                controllerLabel: '',
                controllerName: '',
              }
              if (commandItem['targetComponent']) {
                event['targetComponent'] = commandItem.targetComponent;
              }
              updatedBoundEvents.push(cloneDeep(event));
            }
          });
        }
      });
    });
    return updatedBoundEvents;
  }
  /** 4-4.根据遍历components得出的所有事件，结合webcmd,得到控制器值 */
  matchWebcmd(allBoundEvents) {
    this.webCmds.forEach(webCmdsItem => {
      allBoundEvents.forEach(allBoundEventsItem => {
        if (webCmdsItem.Id == allBoundEventsItem.cmpId) {
          webCmdsItem.Commands.forEach(commandItem => {
            if (commandItem.Code == allBoundEventsItem.handlerName) {
              allBoundEventsItem.controllerId = webCmdsItem.Id;
              allBoundEventsItem.controllerLabel = webCmdsItem.Code;
              allBoundEventsItem.controllerName = webCmdsItem.Name;
            }
          });
        }
      });
    });
    allBoundEvents.forEach(function (allBoundEventsItem, index) {
      //失效命令
      if (allBoundEventsItem.controllerId == '' && allBoundEventsItem.controllerLabel == '' && allBoundEventsItem.controllerName == '') {
        allBoundEvents.splice(index, 1);
      }
    })
    return allBoundEvents;
  }
  /** 4-5.根据遍历components得出的事件的viewmodelId,得到componentId值 */
  getComponentId(allBoundEvents) {
    const components = this.domService.module.components;
    const viewModel = this.domService.module.viewmodels;
    for (let i = 0; i < components.length; i++) {
      allBoundEvents.forEach(allBoundEventsItem => {
        if (viewModel[i] && viewModel[i].id == allBoundEventsItem.viewModelId) {
          allBoundEventsItem.componentId = components[i].id;
        }
      });
    }
    return allBoundEvents;
  }
  /** 4-6.标准样式化actions */
  setActions(allBoundEvents, num, array) {
    let action = {
      sourceComponent: {
        id: '',
        viewModelId: '',
        map: []
      }
    };
    if (!allBoundEvents[num]) {
      return;
    }
    action.sourceComponent.id = allBoundEvents[num].id;
    action.sourceComponent.viewModelId = allBoundEvents[num].viewModelId;
    let i = num;
    while (i < allBoundEvents.length) {
      if (allBoundEvents[i].id == action.sourceComponent.id) {
        let mapItem = {
          event: {
            label: allBoundEvents[i].eventLabel,
            name: allBoundEvents[i].eventName
          },
          targetComponent: {
            id: allBoundEvents[i].componentId,
            viewModelId: allBoundEvents[i].viewModelId
          },
          command: {
            id: allBoundEvents[i].commandId,
            label: allBoundEvents[i].commandLabel,
            name: allBoundEvents[i].commandName,
            handlerName: allBoundEvents[i].handlerName,
            params: cloneDeep(allBoundEvents[i].params),
            cmpId: allBoundEvents[i].cmpId,
            isNewGenerated: allBoundEvents[i].isNewGenerated || false,
            isRTCmd: allBoundEvents[i]['isRTCmd'],
            isInvalid: allBoundEvents[i].isInvalid || false,
          },
          controller: {
            id: allBoundEvents[i].controllerId,
            label: allBoundEvents[i].controllerLabel,
            name: allBoundEvents[i].controllerName
          }
        }
        if (allBoundEvents[i]['componentId']) {
          mapItem.targetComponent.id = allBoundEvents[i].componentId;
        }
        action.sourceComponent.map.push(cloneDeep(mapItem));
        i++;
        if (i == allBoundEvents.length) {
          array.push(cloneDeep(action));
        }
      }
      else {
        array.push(cloneDeep(action));
        this.setActions(allBoundEvents, i, array);
        break;
      }
    }
    return array;
  }

  /** 更新事件编辑器获取到的webcmds */
  webCmdsChanged(newController) {
    newController.forEach(newControllerItem => {
      let item = new WebCommandMetadataConvertor().InitFromJobject(newControllerItem);
      this.webCmds.push(cloneDeep(item));
    });
    this.checkViewModelCommands(this.webCmds);
  }



  /** 
   * 事件面板调用-1
   * a. 合并视图模型带参数的命令&控制器中无参数的命令
   * b. 生成绑定事件列表
   *  */
  findParamtersPosition(propertyData: any, events: any, viewModelId: string, allComponentList: any) {
    this.boundEventsList = [];
    let viewModelData = cloneDeep(this.domService.module.viewmodels);
    //1. 遍历当前container的组件dom结构的所有事件的值
    events.forEach(event => {
      if (propertyData[event.label]) {
        // 三段式path：root-viewmodel.items-component-viewmodel.itemsAddItem1 或 一段path：itemsAddItem1
        let paths = propertyData[event.label].includes('.') ? propertyData[event.label].split('.') : undefined;
        let recordCommand = this.handleParams(viewModelData, paths, propertyData[event.label], viewModelId, allComponentList).recordCommand;
        let recordController = this.handleParams(viewModelData, paths, propertyData[event.label], viewModelId, allComponentList).recordController;
        this.generateBoundEventsList(event, events, recordController, recordCommand);
      }
    });
    return this.boundEventsList;
  }
  /** 1-a.在视图模型中找到命令，并填充参数值*/
  handleParams(viewModelData, paths, propCmdLabel, viewModelId, allComponentList) {
    const vmId = paths != undefined ? paths[1] : viewModelId;
    const cmdLabel = paths != undefined ? paths[2] : propCmdLabel;
    let cmpId;
    if (allComponentList.length && vmId != undefined) {
      const componentList = allComponentList.find(componentListsItem => componentListsItem.viewModelId == vmId);
      cmpId = componentList == undefined ? undefined : componentList.componentId;
    }
    // 若命令不存在，则提示！，并允许用户绑定其他命令
    let recordCommand = {
      id: 'abandoned',
      code: cmdLabel,
      name: cmdLabel,
      params: [],
      handlerName: cmdLabel,
      cmpId: '',
      shortcut: {},
      extensions: [],
      isInvalid: false,
      isNewGenerated: undefined,
      showTargetComponent: false,
      targetComponent: cmpId,
      isRTCmd: undefined,
    }
    let recordController = {
      controllerName: {
        label: '',
        name: '',
        id: '',
      },
      controllerList: {
      },
      boundEvents: {
      }
    }
    viewModelData.forEach(element => {
      //5. 寻找命令-确认itemsAddItem1的位置
      if (element.code.includes(vmId)) {
        element.commands.forEach(viewModelcommand => {
          //6-1. 若命令存在，且参数不为空
          if (viewModelcommand.code == cmdLabel && viewModelcommand.params.length != 0) {
            //判断是否为已失效命令
            if (!viewModelcommand['isInvalid']) {
              //7-1. 若存在参数，则合并该命令在VM与控制器中的参数值
              viewModelcommand.params.forEach(param => {
                // 7-1-1.handlerName唯一，code为带前后缀的命令英文名，name为中文名，param是当前待合并的参数（有值）
                recordController = this.combinedParamters(param, viewModelcommand, recordController, recordCommand, cmpId).recordController;
                recordCommand = this.combinedParamters(param, viewModelcommand, recordController, recordCommand, cmpId).recordCommand;
              });
            }
            else {
              //命令已被删除
              recordCommand.id = 'deleted'
            }
          }
          //6-2 若命令存在，且参数为空的处理
          else if (viewModelcommand.code == cmdLabel && viewModelcommand.params.length == 0) {
            //判断是否为已失效命令
            if (!viewModelcommand['isInvalid']) {
              //7-2. 不需要进行内置构件的处理，仅记录了命令所在的控制器及带前后缀的命令名称
              this.internalCommandList.forEach(controller => {
                if (controller.controllerName.id == viewModelcommand.cmpId) {
                  controller.controllerList.forEach(command => {
                    if (command.handlerName == viewModelcommand.handlerName) {
                      recordController = cloneDeep(controller);
                      recordCommand = this.getRecordController(command, viewModelcommand, recordCommand, cmpId);
                    }
                  })
                }
              })
            } else {
              //命令已被删除
              recordCommand.id = 'deleted'
            }
          }
        });

      }
    });
    return {
      recordController,
      recordCommand
    };
  }
  /** 1-a.合并视图模型带参数的命令&控制器中无参数的命令 */
  combinedParamters(paramWithValue: any, viewModelcommand, recordController, recordCommand, cmpId) {
    //7-1-2. handlerName唯一，code为带前后缀的命令英文名，paramWithValue是当前待合并的参数（有值）
    this.internalCommandList.forEach(controller => {
      //控制器相同
      if (controller.controllerName.id == viewModelcommand.cmpId) {
        controller.controllerList.forEach(command => {
          //7-1-3. command.handlerName来自内置构件；handlerName来自视图模型
          if (command.handlerName == viewModelcommand.handlerName) {
            command.property.forEach(paramWithoutValue => {
              if (paramWithoutValue.name == paramWithValue.name) {
                paramWithoutValue.value = cloneDeep(paramWithValue.value);
              }
            });
            recordController = cloneDeep(controller);
            recordCommand = this.getRecordController(command, viewModelcommand, recordCommand, cmpId);
          }
        });
      }
    })
    return {
      recordController,
      recordCommand
    }
  }
  /** 1-a.存储绑定事件对应的控制器参数值 */
  getRecordController(command, viewModelcommand, recordCommand, cmpId) {
    // 1-a-1. 由于vm未记录控制器，此处根据命令找到控制器，并将有值的参数对应的命令command记录
    recordCommand = cloneDeep(command);
    // 1-a-2.记录带前后缀的英文名、中文名/参数
    recordCommand.label = viewModelcommand.code;
    recordCommand.name = viewModelcommand.name;
    recordCommand.id = viewModelcommand.id;
    recordCommand.targetComponent = cmpId;
    recordCommand['isRTCmd'] = viewModelcommand['isRTCmd'];
    return recordCommand;
  }
  /** 1-b.生成已绑定的事件列表 */
  generateBoundEventsList(event, events, recordController, recordCommand) {
    if (recordController != undefined) {
      let boundEventsListItem = {
        controllerList: {
        },
        controllerName: {
        },
        boundEvents: {
        }
      }
      events.forEach(each => {
        if (each.label == event.label) { boundEventsListItem.boundEvents = cloneDeep(each); }
      });
      boundEventsListItem.controllerName = cloneDeep(recordController.controllerName);
      boundEventsListItem.controllerList = cloneDeep(recordCommand);
      this.boundEventsList.push(cloneDeep(boundEventsListItem));
    }
  }

  /** 事件面板调用-2
   * 2-a.找到视图模型，在视图模型中增删改命令及参数 */
  viewModelDomChanged(propertyData: any, events: any, viewModelId: string, domActions: any) {
    let viewModelData = cloneDeep(this.domService.module.viewmodels);
    events.forEach(event => {
      //1. 遍历当前container的dom结构的所有事件的值
      if (propertyData[event.label]) {
        // 三段式path：root-viewmodel.items-component-viewmodel.itemsAddItem1 或 一段path：itemsAddItem1
        let paths = propertyData[event.label].includes('.') ? propertyData[event.label].split('.') : undefined;
        this.handleViewModel(viewModelData, paths, propertyData[event.label], viewModelId, domActions, propertyData);
      }
    });
    this.domService.module.viewmodels = cloneDeep(viewModelData);
  }
  /** 2-a.在视图模型中增删改命令及参数 */
  handleViewModel(viewModelData, paths, propCmdLabel, viewModelId, domActions, propertyData) {
    let newCommand = {
      id: '',
      code: '',
      name: '',
      params: [],
      handlerName: '',
      cmpId: '',
      shortcut: {},
      extensions: [],
      isInvalid: false,
      isNewGenerated: undefined,
      targetComponent: undefined,
      isRTCmd: undefined,
    }
    const vmId = paths != undefined ? paths[1] : viewModelId;
    const cmdLabel = paths != undefined ? paths[2] : propCmdLabel;
    // 4. 遍历找到存储命令的第二层path——path[1]，viewModel的items-component-viewmodel
    viewModelData.forEach(element => {
      if (element.code.includes(vmId)) {
        let commandExist = false;
        //5. 借助整体dom中的domActions节点，寻找命令-确认itemsAddItem1的位置
        domActions.forEach(action => {
          //6. 匹配domActions，取出所有需要的值，包括命令名/事件名/参数/id等等；
          if (action.sourceComponent.id == propertyData.id) {
            action.sourceComponent.map.forEach(mapItem => {
              if (mapItem.command.label == cmdLabel) {
                newCommand.id = cloneDeep(mapItem.command.id);
                newCommand.code = mapItem.command.label;
                newCommand.name = mapItem.command.name;
                newCommand.params = this.serializeParameter(mapItem.command.params);
                newCommand.handlerName = mapItem.command.handlerName;
                newCommand.cmpId = cloneDeep(mapItem.controller.id);
                newCommand.shortcut = mapItem.command.shortcut;
                newCommand.isRTCmd = mapItem.command['isRTCmd'];
                newCommand.isNewGenerated = mapItem.command.isNewGenerated || false;
                newCommand.isInvalid = mapItem.command.isInvalid || false;
                newCommand.extensions = mapItem.command.extensions;
                if (mapItem.command.isInvalid) {
                  newCommand.isInvalid = mapItem.command.isInvalid;
                }
                newCommand.targetComponent = mapItem.targetComponent.id;
              }
            });
          }
        });
        //7-1. 匹配viewModel中存储的是否有该命令：itemsAddItem1，若存在该命令，则更新新的值
        element.commands.forEach(function (command, index) {
          if (command.code == cmdLabel) {
            commandExist = true;
            element.commands.splice(index, 1, cloneDeep(newCommand));
          }
        });
        //7-2. 若没有该命令，则进行添加
        if (!commandExist) {
          element.commands.push(cloneDeep(newCommand));
        }
      }
      //8-1. 剪切掉其他同名称的命令
      else {
        //8-1. 匹配其他viewModel中是否有同名称的命令，若有，则删除；
        element.commands.forEach(function (command, index) {
          if (command.code == cmdLabel) {
            element.commands.splice(index, 1);
          }
        });
      }
    });
  }


  /** 事件面板调用-3
   * 3-a.存储事件编辑器「视图模型」中所有的viewModel数据 */
  viewModelDisplay() {
    let savedViewModel = [];
    const savedViewModelItem = {
      controllerName: {
        label: '',
        name: '',
        id: '',
      },
      controllerList: [
      ]
    }
    /** 控制器下的命令列表 */
    let controllerListItem = {
      label: '',
      name: '',
      id: '',
      handlerName: '',
      showTargetComponent: false,
      isNewGenerated: undefined,
      isRTCmd: undefined,
      isInvaild: false,
      cmpId: '',
      componentLists: [],
      targetComponent: undefined,
      property: [

      ]
    }
    if (!this.domService.module.actions) {
      return savedViewModel;
    }
    this.domService.module.actions.forEach(actionItem => {
      actionItem.sourceComponent.map.forEach(mapItem => {
        savedViewModelItem.controllerName.id = mapItem.controller.id;
        savedViewModelItem.controllerName.name = mapItem.controller.name;
        savedViewModelItem.controllerName.label = mapItem.controller.label;
        savedViewModel.push(cloneDeep(savedViewModelItem));
        savedViewModel = this.getUniqueController(savedViewModel);
      });
    })
    savedViewModel.forEach(savedViewModelItem => {
      this.domService.module.actions.forEach(actionItem => {
        actionItem.sourceComponent.map.forEach(mapItem => {
          if (mapItem.controller.id == savedViewModelItem.controllerName.id) {
            controllerListItem.label = mapItem.command.label;
            controllerListItem.name = mapItem.command.name;
            controllerListItem.id = mapItem.command.id;
            controllerListItem.handlerName = mapItem.command.handlerName;
            controllerListItem.property = cloneDeep(mapItem.command.params);
            controllerListItem.cmpId = mapItem.controller.id;
            controllerListItem.isNewGenerated = mapItem.isNewGenerated || false;
            controllerListItem.isRTCmd = mapItem['isRTCmd'];
            controllerListItem.isInvaild = mapItem.inInvalid || false;
            if (mapItem.targetComponent.id) {
              controllerListItem.targetComponent = mapItem.targetComponent.id;
            } else {
              controllerListItem.targetComponent = undefined;
            }
            savedViewModelItem.controllerList.push(cloneDeep(controllerListItem))
          }
        })
      })
    });
    return savedViewModel;
  }

  /** 去重 */
  getUniqueController(itemWithSameValue) {
    let value = cloneDeep(itemWithSameValue);
    for (let i = 0; i < value.length; i++) {
      for (let j = i + 1; j < value.length; j++) {
        if (value[i]['controllerName']['id'] == value[j]['controllerName']['id']) {
          value.splice(j, 1);
          j--;
        }
      }
    }
    itemWithSameValue = cloneDeep(value);
    return itemWithSameValue;
  }

  /** 触发新增控制器方法 */
  addControllerMethod(propertyData: any, viewModelId: string, parameters: any) {
    const { methodCode, methodName } = this.resolveNewMethodForCodeEditor(propertyData, viewModelId, parameters);
    // this.webCmpBuilderService.addControllerMethod(methodCode, methodName);
  }
  /**
   * 序列化视图模型中的命令参数
   * @param parameters 参数
   * @returns 
   */
  private serializeParameter(parameters: any[]) {
    const results = [];
    if (parameters && Array.isArray(parameters) && parameters.length > 0) {
      parameters.forEach(parameter => {
        const item: any = {};
        if (parameter.hasOwnProperty('name')) {
          item.name = parameter.name;
        }
        if (parameter.hasOwnProperty('shownName')) {
          item.shownName = parameter.shownName;
        }
        if (parameter.hasOwnProperty('value')) {
          item.value = parameter.value;
        }
        results.push(item);
      });
    }
    return results;
  }

  /**
   * 交互面板跳转到代码视图前，收集控件信息，用于自动绑定新增的方法
   * @param propertyData 控件schema值
   * @param viewModelId 控件所属视图模型id
   * @param parameters 点击添加新方法后，交互面板返回的参数
   * @param controlTypeName 控件类型名称
   */
  public resolveNewMethodForCodeEditor(propertyData: any, viewModelId: string, parameters: any): { methodCode: string, methodName: string } {
    const eventCode = parameters.newFuncEvents && parameters.newFuncEvents.label || '';
    const eventName = parameters.newFuncEvents && parameters.newFuncEvents.name || '';
    const upperEventCode = eventCode.length > 1 ? (eventCode.slice(0, 1).toUpperCase() + eventCode.slice(1)) : eventCode;

    let methodCode = 'method';
    let methodName = '方法';

    // 方法编号：控件类型+事件编号；方法名称：控件名称+事件名称
    const controlInfo = parameters.controlInfo;
    if (controlInfo) {
      const controlType = controlInfo.type;
      const controlName = propertyData.title || propertyData.text || propertyData.caption || controlInfo.name;
      if (controlType && controlType.length > 1 && controlName) {
        const lowerControlType = controlType.slice(0, 1).toLowerCase() + controlType.slice(1);
        methodCode = `${lowerControlType}${upperEventCode}`.replace(/_/g, '').replace(/-/g, '');
        methodName = `${controlName}${eventName}`.replace(/_/g, '').replace(/-/g, '');

      }
    }

    this.newControllerMethodBindingInfo = {
      controlData: propertyData,
      viewModelId,
      componentId: this.domService.getComponentByVMId(viewModelId).id,
      eventCode,
      methodCode,
      methodName,
      setPropertyRelates: parameters.setPropertyRelates
    };

    return { methodCode, methodName };
  }

  /**
   * 代码视图返回新增方法的编号、名称后，由设计器将方法添加到控件上
   * @param methodCode 新增方法的编号
   * @param methodName 新增方法的名称
   */
  bindNewMethodToControl(methodCode: string, methodName: string) {
    if (!this.newControllerMethodBindingInfo) {
      return;
    }
    const commandBuildInfo = this.webCmpBuilderService.buildInfo;
    if (!commandBuildInfo || !commandBuildInfo.webCmdId) {
      return;
    }
    const { eventCode, viewModelId } = this.newControllerMethodBindingInfo;
    const viewModel = this.domService.getViewModelById(viewModelId);

    // 1、控件绑定命令
    this.newControllerMethodBindingInfo.controlData[eventCode] = methodCode;

    // 2、控件绑定命令后，可能会需要联动其他属性的变更
    if (this.newControllerMethodBindingInfo.setPropertyRelates) {
      this.newControllerMethodBindingInfo.setPropertyRelates(null, this.newControllerMethodBindingInfo.controlData, null);
    }

    // 3、视图模型添加命令
    let commandId = new IdService().generate();
    const viewModelCommand = viewModel.commands.find(co => co.code === methodCode && co.handlerName === methodCode && co.cmpId === commandBuildInfo.webCmdId);
    if (!viewModelCommand) {
      viewModel.commands.push(
        {
          id: commandId,
          code: methodCode,
          name: methodName,
          params: [],
          handlerName: methodCode,
          cmpId: commandBuildInfo.webCmdId,
          shortcut: {},
          extensions: []
        }
      );
    } else {
      commandId = viewModelCommand.id;
    }



    // 4、webCmd添加构件
    if (this.domService.module.webcmds) {
      let customCmd = this.domService.module.webcmds.find(cmd => cmd.id === commandBuildInfo.webCmdId);
      if (!customCmd) {
        customCmd = {
          id: this.webCmpBuilderService.buildInfo.webCmdId,
          path: commandBuildInfo.relativePath,
          name: `${commandBuildInfo.code}.webcmd`,
          refedHandlers: []
        };
        this.domService.module.webcmds.push(customCmd);
      }
      if (!customCmd.refedHandlers.find(handler => handler.host === commandId && handler.handler === methodCode)) {
        customCmd.refedHandlers.push(
          {
            host: commandId,
            handler: methodCode
          }
        );
      }
    }

    this.newControllerMethodBindingInfo = null;
  }
}
